#![allow(dead_code)]

struct TimeLrn {}

impl TimeLrn {
    fn hello() {
        println!("Time learning!");
    }
}

fn timer<F, T>(f: F) -> impl Fn(T, T) -> T
where
    F: Fn(T, T) -> T,
    T: std::fmt::Debug + Copy + Clone,
{
    move |a, b| {
        let now = std::time::Instant::now();
        let out = f(a, b);
        println!("{}", "-".repeat(40));
        println!("Time elapsed: {}", now.elapsed().as_secs());
        println!("{}", "-".repeat(40));
        out
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread::sleep;

    #[test]
    /// # time_test
    ///
    /// This test function demonstrates the usage of `std::time::Instant` and `std::time::Duration` in Rust.
    ///
    /// It creates an `Instant` object `now` representing the current point in time, then puts the thread to sleep for a little over 1 second.
    ///
    /// After the sleep, it creates another `Instant` object `new_now` and prints the elapsed time since `now` in seconds.
    ///
    /// It also prints the `Duration` from `now` to `new_now` and from `new_now` to `now`. The latter should be close to zero as `new_now` is a later point in time.
    ///
    /// Note: The actual sleep time may be slightly more than 1 second due to the way OS schedules threads.
    fn time_test() {
        let now = std::time::Instant::now();
        sleep(std::time::Duration::new(1, 5));
        let new_now = std::time::Instant::now();
        println!("{:?}", now.elapsed().as_secs());
        println!("{:?}", new_now.duration_since(now));
        println!("{:?}", now.duration_since(new_now)); // 反着算是0
    }

    #[test]
    /// # timer_test
    ///
    /// This function demonstrates the usage of the `timer` macro.
    ///
    /// It defines a simple function `add` that takes two `i32` arguments, sleeps for 2 seconds, and then returns their sum.
    ///
    /// The `timer` macro is then used to wrap the `add` function, creating a new function `add_2_nums`. This new function behaves like `add`, but also prints the time it took to execute.
    ///
    /// The `add_2_nums` function is then called with the arguments 1 and 2, and the result is printed.
    ///
    /// Note: The actual sleep time may be slightly more than 2 seconds due to the way the OS schedules threads.
    fn timer_test() {
        fn add(a: i32, b: i32) -> i32 {
            sleep(std::time::Duration::from_secs(2));
            a + b
        }

        // * decorator
        let add_2_nums = timer(add);

        let res = add_2_nums(1, 2);
        println!("result: {}", res);
    }
}
